package com.wave.gate.mqtt.client;


import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.alibaba.fastjson2.JSON;
import com.wave.gate.constant.CommonConstants;
import com.wave.gate.enums.ConveyerEnum;
import com.wave.gate.enums.RedisKeyEnum;
import com.wave.gate.init.InitBaseInfo;
import com.wave.gate.util.*;
import com.wave.gate.vo.GatePassSetVo;
import com.wave.gate.vo.GatePassWeightParamVo;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

import static com.wave.gate.util.GuavaCache.DOOR_MODE_CACHE;

@Component
@Slf4j
public class MqttAcceptCallback implements MqttCallbackExtended {



    @Autowired
    private MqttAcceptClient mqttAcceptClient;

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Value("${electronicBalance.index}")
    public int electronicBalanceIndex;

    @Value("${wave.door.security.http}")
    private String http;

    @Value("${mp3.file.path}")
    private String path;

    @Value("${electronicBalance.mobile.error}")
    private Double mobileError;

    @Value("${electronicBalance.token.error}")
    private Double tokenError;

    /**
     * 客户端断开后触发
     *
     * @param throwable
     */
    @Override
    public void connectionLost(Throwable throwable) {
        log.info("连接断开，可以做重连");
    }

    /**
     * 客户端收到消息触发
     *
     * @param topic       主题
     * @param mqttMessage 消息
     */
    @Override
    public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
        log.info("接收消息主题 : " + topic);
        log.info("接收消息Qos : " + mqttMessage.getQos());
        log.info("接收消息内容 : " + new String(mqttMessage.getPayload()));
        try {
            String type = new String(mqttMessage.getPayload());
            String ipAddress = InitBaseInfo.ipAddress;//本地ip
            if(topic.equals("wave-gate:plcGetSomething:" + ipAddress)){//plc传送带取出物体，type=7入口，type=8出口
                getSomething(type);
            }
            if(topic.equals("wave-gate:balanceZero:" + ipAddress)){//电子秤置零，type=1入口电子秤，type=5出向电子秤
                balanceZero(type);
            }
            if(topic.equals("wave-gate:controllDoor:" + ipAddress)){//远程操控闸机：1-核验模式、2-常开、3-常闭、4-开门60秒
                controllDoor(Integer.parseInt(type));
            }
            if(topic.equals("wave-gate:passsetipInfo:" + ipAddress)){//该套设备ip
                GuavaCache.PASSSET_CACHE.put("passsetipInfo", JSON.parseObject(type, GatePassSetVo.class));
            }
            if(topic.equals("wave-gate:mobileTokenweightList")){//清理重量信息，等定时任务更新
                mobileTokenweightList();
            }
            if(topic.equals("wave-gate:voicePush")){//同步语音
                voicePush(type);
            }

        } catch (Exception e) {
            log.error("messageArrived error:[{}]",e.getMessage(),e);
        }
    }

    private void mobileTokenweightList() {
        GuavaCache.MOBILE_TOKEN_WEIGHTLIST_CACHE.invalidateAll();
        String url = http + "/wave-gate/device/cache";
        //设置请求参数   前后端约定通过json格式传递参数，此时就不能用form方法了，改用它提供的body方法
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("deviceIP", InitBaseInfo.ipAddress);
        paramsMap.put("queryIps", 1);
        paramsMap.put("queryWeight", 2);
        paramsMap.put("mobileError", mobileError);
        paramsMap.put("tokenError", tokenError);
        HttpResponse execute = HttpUtils.httpCache(url, paramsMap);
        if(execute.isOk()){
            String body = execute.body();   // 获取响应主体
            log.info("最新的手机、token重量误差集合结果：" + body);
            Map<String, String> map = JSON.parseObject(body, HashMap.class);
            if("200".equals(map.get("code"))) {
                GuavaCache.MOBILE_TOKEN_WEIGHTLIST_CACHE.put("mobileTokenweightList",
                        JSON.parseArray(map.get("mobileTokenweightList"), GatePassWeightParamVo.class));
            }
        }

    }

    private void voicePush(String type) {
        String url = type.split("&")[0];
        String fileName = type.split("&")[1];
        FileUtil.writeBytes(HttpUtil.downloadBytes(http + url),path + fileName);
    }

    //远程操控：1-核验模式、2-常开、3-常闭、4-开门60秒
    private void controllDoor(int workMode) throws IOException {
        //A门闸机端口
        int gateAPort = 502;

        //B门闸机端口
        int gateBPort = 502;
        //00：常开；11：进向自由、出向自由
        String doorCommand1 = "000000000006010600410011";

        //01：常关；22：进向禁止、出向禁止
        String doorCommand2 = "000000000006010600410122";

        //01：核验；22：进向禁止、出向禁止
        String doorCommand3 = "000000000006010600410122";

        GatePassSetVo gatePassSetVo = GuavaCache.PASSSET_CACHE.getIfPresent("passsetipInfo");
        String gateAIp = gatePassSetVo.getInGateIp();//A门闸机IP
        String gateBIp = gatePassSetVo.getOutGateIp();//B门闸机IP
        Socket doorA = null;
        Socket doorB = null;
        try {
            doorA = new Socket(gateAIp, gateAPort);
            doorB = new Socket(gateBIp, gateBPort);
            DOOR_MODE_CACHE.put(RedisKeyEnum.KEY_REMOTE_CONTROLL.getCode(), workMode);
            if (workMode == 2) {
                String isSuccess_A = SocketClientUtil.sendData(doorA, doorCommand1);
                log.info("A门闸机常开:" + isSuccess_A);
                String isSuccess_B =SocketClientUtil.sendData(doorB, doorCommand1);
                log.info("B门闸机常开:" + isSuccess_B);
            } else if (workMode == 3) {
                String isSuccess_A = SocketClientUtil.sendData(doorA, doorCommand2);
                log.info("A门闸机常闭:" + isSuccess_A);
                String isSuccess_B = SocketClientUtil.sendData(doorB, doorCommand2);
                log.info("B门闸机常闭:" + isSuccess_B);
            } else if (workMode == 4) {
                String isSuccess_A = SocketClientUtil.sendData(doorA, doorCommand1);
                log.info("A门闸机打开60秒开始:" + isSuccess_A);
                String isSuccess_B = SocketClientUtil.sendData(doorB, doorCommand1);
                log.info("B门闸机打开60秒开始:" + isSuccess_B);

                threadPoolTaskExecutor.execute(()->{
                    Socket finalDoorA = null;
                    Socket finalDoorB = null;
                    try {
                        finalDoorA = new Socket(gateAIp, gateAPort);;
                        finalDoorB = new Socket(gateBIp, gateBPort);
                        Thread.sleep(60 * 1000);
                        SocketClientUtil.sendData(finalDoorA, doorCommand2);
                        log.info("A门闸机打开60秒结束" );
                        SocketClientUtil.sendData(finalDoorB, doorCommand2);
                        log.info("B门闸机打开60秒结束");
                        DOOR_MODE_CACHE.put(RedisKeyEnum.KEY_REMOTE_CONTROLL.getCode(), 1);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }finally {
                        try {
                            if (finalDoorA != null) {
                                finalDoorA.close();
                            }
                            if (finalDoorB != null) {
                                finalDoorB.close();
                            }
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    }
                });

            }else {
                log.info("开启核验模式");
                String isSuccess_A = SocketClientUtil.sendData(doorA, doorCommand3);
                log.info("A门闸机开启核验模式:" + isSuccess_A);
                String isSuccess_B = SocketClientUtil.sendData(doorB, doorCommand3);
                log.info("B门闸机开启核验模式:" + isSuccess_B);
            }

        } finally {
            if (doorA != null) {
                doorA.close();
            }
            if (doorB != null) {
                doorB.close();
            }
        }
    }

    private void balanceZero(String type) throws InterruptedException {

        if("1".equals(type)){
            String zeroorder = CommonConstants.ZEROORDER1_1;
            if(electronicBalanceIndex == 2){
                zeroorder = CommonConstants.ZEROORDER2_1;
            }
            NorcoAPIUtil.electronicBalanceSendData(CommonConstants.COM_NODE0, zeroorder);
        }
        if("5".equals(type)){
            String zeroorder = CommonConstants.ZEROORDER1_2;
            if(electronicBalanceIndex == 2){
                zeroorder = CommonConstants.ZEROORDER2_2;
            }
            NorcoAPIUtil.electronicBalanceSendData(CommonConstants.COM_NODE0, zeroorder);
        }

        //老电子秤（暂时没用了）
        //电子秤1归零指令正常返回结果为：01050009FF005C38
        //电子秤2归零指令正常返回结果为：02050009FF005C0B
        String deviceData = NorcoAPIUtil.getDeviceData(5);
        if(("1".equals(type) && "01050009FF005C38".equals(deviceData)) ||
                ("5".equals(type) && "02050009FF005C0B".equals(deviceData))) {
            log.info("电子秤置零成功");
        }

        //新电子秤
        //电子秤1归零指令正常返回结果为：013102510372
        //电子秤2归零指令正常返回结果为：013202510372
        else if(("1".equals(type) && "013102510372".equals(deviceData)) ||
                ("5".equals(type) && "013202510372".equals(deviceData))) {
            log.info("电子秤置零成功");
        }else {
            log.info("电子秤置零失败");
        }
    }

    private void getSomething(String type) throws IOException {
        Socket conveyer = null;
        try {
            //左进右出0->1->2/3   右进左出4->5->2/3
            //0->1/7    4->5/8

            GatePassSetVo gatePassSetVo = GuavaCache.PASSSET_CACHE.getIfPresent("passsetipInfo");

            conveyer = new Socket(gatePassSetVo.getPclIp(), 502);
            String str = "";
            if("1".equals(type)){
                // 0 1 2
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M0.getCode());
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M1.getCode());
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M2.getCode());
            }
            if("2".equals(type)){
                // 0 1 3
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M0.getCode());
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M1.getCode());
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M3.getCode());
            }

            if("3".equals(type)){
                // 4 5 2
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M4.getCode());
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M5.getCode());
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M2.getCode());
                //            Thread.sleep(300);
            }

            if("4".equals(type)){
                // 4 5 3
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M4.getCode());
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M5.getCode());
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M3.getCode());
                //            Thread.sleep(300);
            }

            if("5".equals(type)){
                // 0  7
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M0.getCode());
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M7.getCode());
                //            Thread.sleep(300);
            }

            if("6".equals(type)){
                // 4  8
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M4.getCode());
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M8.getCode());
                //            Thread.sleep(300);
            }

            if("7".equals(type)){
                // M9左侧强制退出
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M9.getCode());
            }

            if("8".equals(type)){
                // M10右侧强制退出
                //            Thread.sleep(300);
                str = SocketClientUtil.sendData(conveyer, ConveyerEnum.CONVEYER_COMMAND_M10.getCode());
            }
        } catch (IOException e) {
            log.error("test conveyer error: [{}]",e.getMessage(),e);
        }finally {
            if(conveyer != null){
                conveyer.close();
            }
        }
    };


    /**
     * 发布消息成功
     *
     * @param token token
     */
    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        String[] topics = token.getTopics();
        for (String topic : topics) {
            log.info("向主题：" + topic + "发送消息成功！");
        }
        try {
            MqttMessage message = token.getMessage();
            byte[] payload = message.getPayload();
            String s = new String(payload, "UTF-8");
            log.info("消息的内容是：" + s);
        } catch (MqttException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 连接emq服务器后触发
     *
     * @param b
     * @param s
     */
    @Override
    public void connectComplete(boolean b, String s) {
        log.info("--------------------ClientId:"
                + MqttAcceptClient.client.getClientId() + "客户端连接成功！--------------------");
        // 以/#结尾表示订阅所有以test开头的主题
        // 订阅所有机构主题plcGetSomething
        mqttAcceptClient.subscribe("wave-gate:plcGetSomething:" + InitBaseInfo.ipAddress, 1);
        mqttAcceptClient.subscribe("wave-gate:balanceZero:" + InitBaseInfo.ipAddress, 1);
        mqttAcceptClient.subscribe("wave-gate:controllDoor:" + InitBaseInfo.ipAddress, 1);
        mqttAcceptClient.subscribe("wave-gate:passsetipInfo:" + InitBaseInfo.ipAddress, 1);
        mqttAcceptClient.subscribe("wave-gate:mobileTokenweightList", 1);
        mqttAcceptClient.subscribe("wave-gate:voicePush", 1);
    }
}

